package com.lxw.multidb.modules.file;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * MinIO对象树节点
 * <p>
 * 核心属性：
 * - 基本信息：name（名称）、fullPath（完整路径）、directory（是否为目录）
 * - 文件属性：size（大小）、extension（扩展名）、lastModified（修改时间）
 * - 树结构：children（子节点列表）、hasChildren（是否有子节点）
 * - 懒加载：childrenLoaded（子节点是否已加载）
 *
 * @author lxw
 * @version 3.0
 * @date 2025-11-06
 */
@Data
public class TreeNode {

    /**
     * 节点名称（不含路径）
     * <p>
     * 文件："report.pdf"  目录："images"
     */
    private String name;

    /**
     * 完整路径（从桶根目录开始）
     * <p>
     * 文件："data/report.pdf"  目录："data/images/"
     */
    private String fullPath;

    /**
     * 是否为目录
     * <p>
     * 说明：
     * - true：该节点是目录，可能包含子节点
     * - false：该节点是文件，不包含子节点
     * <p>
     */
    private boolean directory;

    /**
     * 文件大小（字节）
     * <p>
     * 文件：实际大小  目录：默认为0
     */
    private long size;

    /**
     * 格式化后的文件大小
     * <p>
     * 自动根据size计算，如："2.50 MB"
     */
    private String formattedSize;

    /**
     * 最后修改时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date lastModified;

    /**
     * 文件扩展名（小写，不带点）
     * <p>
     * "report.pdf" → "pdf"  "README" → null
     */
    private String extension;

    /**
     * 子节点列表
     */
    private List<TreeNode> children;

    /**
     * 是否已加载子节点
     * <p>
     * 懒加载标识：
     * - false：子节点未加载，需要时调用loadChildren()
     * - true：子节点已加载，children列表是最新的
     * <p>
     */
    private boolean childrenLoaded;

    /**
     * 是否有子节点
     * <p>
     * 说明：
     * - true：该节点有子节点（或假设有）
     * - false：该节点没有子节点
     * <p>
     */
    private boolean hasChildren;

    /**
     * 构造TreeNode对象
     *
     * @param name        节点名称
     * @param fullPath    完整路径
     * @param isDirectory 是否为目录
     */
    public TreeNode(String name, String fullPath, boolean isDirectory) {
        this.name = name;
        this.fullPath = fullPath;
        this.directory = isDirectory;
        this.children = new ArrayList<>();
        this.size = 0L;
        this.childrenLoaded = !isDirectory;
        this.hasChildren = isDirectory;
    }

    /**
     * 添加子节点
     */
    public void addChild(TreeNode child) {
        if (this.children == null) {
            this.children = new ArrayList<>();
        }
        this.children.add(child);
        this.hasChildren = true;
    }

    /**
     * 设置文件大小并自动格式化
     */
    public void setSize(long size) {
        this.size = size;
        this.formattedSize = formatSize(size);
    }

    /**
     * 从文件名中提取扩展名
     * <p>
     * "report.pdf" → "pdf"  "photo.JPG" → "jpg"  "README" → null
     */
    public static String extractExtension(String fileName) {
        int lastDot = fileName.lastIndexOf('.');
        if (lastDot > 0 && lastDot < fileName.length() - 1) {
            return fileName.substring(lastDot + 1).toLowerCase();
        }
        return null;
    }

    /**
     * 格式化文件大小为人类可读格式
     * <p>
     * 512 → "512 B"  2048 → "2.00 KB"  1572864 → "1.50 MB"
     */
    private String formatSize(long size) {
        if (size < 1024) {
            return size + " B";
        } else if (size < 1024 * 1024) {
            return String.format("%.2f KB", size / 1024.0);
        } else if (size < 1024 * 1024 * 1024) {
            return String.format("%.2f MB", size / (1024.0 * 1024));
        } else {
            return String.format("%.2f GB", size / (1024.0 * 1024 * 1024));
        }
    }

    /**
     * 获取子节点数量
     */
    public int getChildrenCount() {
        return children == null ? 0 : children.size();
    }

    /**
     * 字符串表示
     * <p>
     * [DIR] documents  或  [FILE] report.pdf (2.50 MB)
     */
    @Override
    public String toString() {
        return (directory ? "[DIR] " : "[FILE] ") + name +
                (directory ? "" : " (" + formattedSize + ")");
    }
}